# coding:utf-8

from . import api
from flask import g, request, current_app, jsonify, session
from launch.utils.response_code import RET
from launch.utils.commons import login_required
from launch.utils.image_storage import storage
from launch.models import Area, House, Facility, HouseImage, User, Order
from launch import db, constants, redis_store
import re
import json
from datetime import datetime


@api.route("/areas", methods=['get'])
def get_area_info():
    """
    获取城区信息
    :return:
    """
    # 尝试从redis中读取数据
    try:
        res_json = redis_store.get("area_info")
    except Exception as e:
        current_app.logger.error(e)
    else:
        if res_json is not None:
            # redis有缓存数据
            current_app.logger.info("hit redis_area_info")
            return res_json, 200, {"Content-Type": "application/json"}

    try:
        area_li = Area.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    area_dict_li = []
    # 将对象转换为字典
    for area in area_li:
        area_dict_li.append(area.to_dict())

    # 将数据转换为json字符串
    res_dcit = dict(errno=RET.OK, errmsg="true", data=area_dict_li)

    res_json = json.dumps(res_dcit)
    # 将数据保存到redis中
    try:
        redis_store.setex("area_info", constants.AREA_INFO_REDIS_CACHE_EXPIRES, res_json)
    except Exception as e:
        current_app.logger.error(e)

    return res_json, 200, {"Content-Type": "application/json"}


@api.route("/houses/info", methods=['post'])
@login_required
def save_house_info():
    """
    保存房屋的基本信息
    :return:
    """
    user_id = g.user_id
    req_dict = request.get_json()

    if not req_dict:
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")

    title = req_dict.get("title")  # 房屋名称标题
    price = req_dict.get("price")  # 房屋单价
    area_id = req_dict.get("area_id")  # 房屋所属城区的编号
    address = req_dict.get("address")  # 房屋地址
    room_count = req_dict.get("room_count")  # 房屋包含的房间数目
    acreage = req_dict.get("acreage")  # 房屋面积
    unit = req_dict.get("unit")  # 房屋布局
    capacity = req_dict.get("capacity")  # 房屋容纳人数
    beds = req_dict.get("beds")  # 房屋卧床数目
    deposit = req_dict.get("deposit")  # 押金
    min_days = req_dict.get("min_days")  # 最小入住天数
    max_days = req_dict.get("max_days")  # 最大入住天数

    if not all(
            [title, price, area_id, address, room_count, acreage, unit, capacity, beds, deposit, min_days, max_days]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")

    # 判断金额是否正确
    try:
        price = int(float(price))
        deposit = int(float(deposit))
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    # 判断城区id是否存在
    try:
        area = Area.query.get(area_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    if area is None:
        return jsonify(errno=RET.NODATA, errmsg="城区信息有误")

    # 保存房屋信息
    house = House(
        user_id=user_id,
        area_id=area_id,
        title=title,
        address=address,
        price=price,
        room_count=room_count,
        acreage=acreage,
        unit=unit,
        capacity=capacity,
        beds=beds,
        deposit=deposit,
        min_days=min_days,
        max_days=max_days
    )
    # try:
    # db.session.add(house)
    # db.session.commit()
    # except Exception as e:
    # db.session.rollback()
    # current_app.logger.error(e)
    # return jsonify(errno=RET.DBERR, errmsg="保存数据异常")

    # 处理房屋的设施信息
    facility_ids = req_dict.get("facility")

    # 如果用户勾选了设施信息，再保存数据库
    if facility_ids:
        try:
            facilities = Facility.query.filter(Facility.id.in_(facility_ids)).all()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="数据库异常")
        if facilities:
            # 表示有合法的设施数据
            # 保存设施数据
            house.facilities = facilities
    try:
        db.session.add(house)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="保存数据失败")
    return jsonify(errno=RET.OK, errmsg="OK", data={"house_id": house.id})


@api.route("/houses/image", methods=['post'])
def save_house_image():
    """
    保存房屋的图片
    :return:
    """
    image_file = request.files.get("house_image")
    house_id = request.form.get("house_id")
    if not all([image_file, house_id]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")

    # 判断house_id正确性
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    if house is None:
        return jsonify(errno=RET.NODATA, errmsg="房屋不存在")

    image_data = image_file.read()
    # 保存图片到七牛中
    try:
        file_name = storage(image_data)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg="保存图片失败")

    # 保存图片信息到数据库中
    house_image = HouseImage(house_id=house_id, url=file_name)
    db.session.add(house_image)

    # 处理房屋的主图片
    if not house.index_image_url:
        house.index_image_url = file_name
        db.session.add(house)
    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg="保存图片失败")

    image_url = constants.QINIU_URL_DOMAIN + file_name

    return jsonify(errno=RET.OK, errmsg="OK", data={"image_url": image_url})


@api.route("/user/houses", methods=['get'])
@login_required
def get_user_houses():
    """
    获取房东发布的房源信息条目
    :return:
    """
    user_id = g.user_id

    try:
        # House.query.filter_by(user_id=user_id)
        user = User.query.get(user_id)
        houses = user.houses
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取数据失败")

    # 将查询到的房屋信息转换为字典存放到列表中
    houses_list = []
    if houses:
        for house in houses:
            houses_list.append(house.to_basic_dict())

    return jsonify(errno=RET.OK, errmsg="OK", data={"houses": houses_list})


@api.route("/houses/index", methods=['get'])
def get_house_index():
    """
    获取主页幻灯片展示的房屋基本信息
    :return:
    """
    try:
        ret = redis_store.get("home_page_data")
    except Exception as e:
        current_app.logger.error(e)
        ret = None

    if ret:
        ret = ret.decode()
        current_app.logger.info("hit house index info redis")
        return '{"errno":0,"errmsg":"OK","data":%s}' % ret, 200, {"Content-Type": "application/json"}

    else:
        try:
            houses = House.query.order_by(House.order_count.desc()).limit(constants.HOME_PAGE_MAX_HOUSES)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(erno=RET.DBERR, errmsg="查询数据失败")
        if not houses:
            return jsonify(erno=RET.NODATA, errmsg="查询无数据")

        houses_list = []
        for house in houses:
            # 如果房屋为设置主图片，则跳过
            if not house.index_image_url:
                continue
            houses_list.append(house.to_basic_dict())

        json_houses = json.dumps(houses_list)

        try:
            redis_store.setex("home_page_data", constants.HOME_PAGE_DATA_REDIS_EXPIRES, json_houses)
        except Exception as e:
            current_app.logger.error(e)

        return '{"errno":0,"errmsg":"OK","data":%s}' % json_houses, 200, {"Content-Type": "application/json"}


@api.route("/houses/<int:house_id>", methods=['get'])
def get_house_detail(house_id):
    """
    获取房屋详情
    :return:
    """
    user_id = session.get("user_id", "-1")

    if not house_id:
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")

    try:
        ret = redis_store.get("house_info_%s" % house_id)
    except Exception as e:
        current_app.logger.error(e)
        ret = None

    if ret:
        ret = ret.decode()
        print("\n")
        print(ret)
        current_app.logger.info("hit house info redis")
        return '{"errno":0,"errmsg":"OK","data":{"user_id":%s,"house":%s}}' % (user_id, ret), 200, {
            "Content-Type": "application/json"}

    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询数据失败")

    if not house:
        return jsonify(errno=RET.NODATA, errmsg="房屋信息不存在")

    try:
        house_data = house.to_full_dict()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg="数据出错")

    json_house = json.dumps(house_data)
    try:
        redis_store.setex("house_info_%s" % house_id, constants.HOUSE_DETAIL_REDIS_EXPIRE_SECOND, json_house)
    except Exception as e:
        current_app.logger.error(e)

    response = '{"errno":0,"errmsg":"OK","data":{"user_id":%s,"house":%s}}' % (user_id, json_house), 200, {
        "Content-Type": "application/json"}

    return response


# GET /api/v1.0/houses?sd=20181201&ed=20181202&aid=10&sk=new&p=1
@api.route("/houses", methods=['get'])
def get_house_list():
    """
    获取房屋的列表信息(搜索页面)
    :return:
    """
    start_date = request.args.get("sd", "")  # 用户想要的起始的时间
    end_date = request.args.get("ed", "")  # 用户想要的结束时间
    area_id = request.args.get("aid", "")  # 区域编号
    sort_key = request.args.get("sk", "new")  # 排序关键字
    page = request.args.get("p")  # 页数

    # 处理时间
    try:
        if start_date:
            start_date = datetime.strptime(start_date, "%Y-%m-%d")
        if end_date:
            end_date = datetime.strptime(end_date, "%Y-%m-%d")

        if start_date and end_date:
            # 断言使用
            assert start_date <= end_date
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="日期参数有误")

    # 判断区域编号

    try:
        area = Area.query.get(area_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="区域信息有误")

    # 处理页数
    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        page = 1

    # 使用缓存，获取缓存数据
    redis_key = "house_%s_%s_%s_%s" % (start_date, end_date, area_id, sort_key)

    try:
        response_json = redis_store.hget(redis_key, page)
    except Exception as e:
        current_app.logger.error(e)
    else:
        if response_json:
            return response_json, 200, {"Content-Type": "application/json"}

    # 过滤条件的参数列表容器
    filter_params = []

    # 填充过滤参数
    # 时间条件
    conflict_orders = None

    try:
        # 填充过滤参数
        if start_date and end_date:
            # 查询冲突的订单
            conflict_orders = Order.query.filter(Order.begin_date <= end_date, Order.end_date >= start_date).all()

        elif start_date:
            # 查询冲突的订单
            conflict_orders = Order.query.filter(Order.end_date >= start_date).all()
        elif end_date:
            # 查询冲突的订单
            conflict_orders = Order.query.filter(Order.begin_date <= end_date).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    if conflict_orders:
        # 从订单中获取冲突的房屋id
        # 列表推导式
        conflict_house_ids = [order.house_id for order in conflict_orders]

        # 如果冲突的房屋id不为空，向查询参数中添加条件
        if conflict_house_ids:
            filter_params.append(House.id.notin_(conflict_house_ids))

    # 区域条件
    if area_id:
        filter_params.append(House.area_id == area_id)

    # 查询数据库
    # 补充排序条件
    if sort_key == "booking":  # 入住最多
        house_query = House.query.filter(*filter_params).order_by(House.order_count.desc())
    elif sort_key == "price-inc":
        house_query = House.query.filter(*filter_params).order_by(House.price)
    elif sort_key == "pricce-des":
        house_query = House.query.filter(*filter_params).order_by(House.price.desc())
    else:
        house_query = House.query.filter(*filter_params).order_by(House.create_time.desc())

    # 处理分页
    try:
        #                               当前页数            每页数据量                               自动的错误输出
        page_obj = house_query.paginate(page=page, per_page=constants.HOUSE_LIST_PAGE_CAPACITY, error_out=False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    # 获取页面数据
    house_li = page_obj.items
    houses = []
    for house in house_li:
        houses.append(house.to_basic_dict())

    # 获取总页数
    total_page = page_obj.pages
    # return jsonify(errno=RET.OK, errmsg="OK", data={"total_page": total_page, "houses": houses, "current_page": page})
    response_dict = dict(errno=RET.OK, errmsg="OK",
                         data={"total_page": total_page, "houses": houses, "current_page": page})

    response_json = json.dumps(response_dict)
    # 设置缓存数据
    redis_key = "house_%s_%s_%s_%s" % (start_date, end_date, area_id, sort_key)
    # 哈希类型
    try:
        # redis_store.hset(redis_key, page, response_json)
        # redis_store.expire(redis_key, constants.HOUSE_LIST_PAGE_REDIS_CACHE_RXPIRES)
        # 创建redis管道对象，可以一次执行多个语句
        pipeline = redis_store.pipeline()
        # 开启多个语句的记录
        pipeline.multi()
        pipeline.hset(redis_key, page, response_json)
        pipeline.expire(redis_key, constants.HOUSE_LIST_PAGE_REDIS_CACHE_RXPIRES)
        # 执行语句
        pipeline.execute()

    except Exception as e:
        current_app.logger.error(e)

    return response_json, 200, {"Content-Type": "application/json"}
